// Copyright (C) 1953-2020 NUDT
// Verilog module name - HOI 
// Version: HOI_V1.0
// Created:
//         by - jintao peng 
//         at - 08.2020
////////////////////////////////////////////////////////////////////////////
// Description:
//		   output process of host interface.
//             - receive pkt,and transmit pkt to PHY;
//		       - record timestamp for PTP packet;
//		   	   - add preamble of frame and start-of-frame delimiter before transmitting pkt;
//             - control interframe gap that is 12 cycles.
///////////////////////////////////////////////////////////////////////////

`timescale 1ns/1ps

module output_width_transform
(
        i_clk,
        i_rst_n,
	    
        iv_syn_clk,
        iv_local_clk,
        
        iv_pkt_data,
        o_pkt_data_rd,
        i_pkt_data_empty,
	    
        i_data_ready,
        ov_data     ,
	    o_data_wr   
);
// I/O
// clk & rst
input                  i_clk;	
input                  i_rst_n;

input      [63:0]      iv_local_clk;
input      [63:0]      iv_syn_clk;
// receive pkt 
input      [133:0]     iv_pkt_data;
input                  i_pkt_data_empty;
output reg             o_pkt_data_rd;
// transmit pkt to phy
input                  i_data_ready;	   
output reg [8:0]       ov_data;
output reg             o_data_wr;

//***************************************************
//                 transmit pkt 
//***************************************************
reg                     r_ctrl_or_data_flag;
reg        [63:0]       rv_send_sync_clk;
reg        [63:0]       rv_send_local_cnt;
reg		   [10:0]		rv_send_pkt_cnt;
reg		   [3:0]		rv_trans_pkt_cnt;
reg		   [3:0]        rv_interframe_gap_cnt;
reg		   [63:0]		rv_transparent_clock;
reg		   [18:0]		rv_timer;
reg		   [3:0]		owt_state;
localparam	IDLE_S                 = 4'd0,
			DISC_MD0_S             = 4'd1,
            DISC_MD1_S             = 4'd2,
			TRANS_1ST_S            = 4'd3,
            TRANS_PKT_S            = 4'd4,
			CONTROL_IFG_S = 4'd5;
always @(posedge i_clk or negedge i_rst_n) begin
	if(i_rst_n == 1'b0)begin
        ov_data          <= 9'b0;
		o_data_wr        <= 1'b0;
        o_pkt_data_rd    <= 1'b0;
		rv_trans_pkt_cnt <= 4'd0;
		rv_send_pkt_cnt  <= 11'd0;		
		rv_interframe_gap_cnt <= 4'd0;
        rv_transparent_clock  <= 64'b0;
        
        rv_send_sync_clk     <= 64'b0;
        rv_send_local_cnt   <= 64'b0;
        r_ctrl_or_data_flag  <= 1'b0;
        
		owt_state <= IDLE_S;
	end
	else begin
		case(owt_state)
			IDLE_S:begin
                ov_data               <= 9'b0;
                o_data_wr             <= 1'b0;            
				rv_trans_pkt_cnt      <= 4'd0;
				rv_interframe_gap_cnt <= 4'd0;
                rv_transparent_clock  <= 64'b0;
                rv_send_pkt_cnt       <= 11'd0;
                if((i_pkt_data_empty == 1'b0) && (i_data_ready == 1'b1))begin
                    o_pkt_data_rd         <= 1'b1;                    
                    owt_state             <= DISC_MD0_S;
                end
                else begin                    
                    o_pkt_data_rd         <= 1'b0; 
                    owt_state             <= IDLE_S;
                end
			end
            DISC_MD0_S:begin
                if(i_pkt_data_empty == 1'b0)begin
                    o_pkt_data_rd         <= 1'b1;                    
                    r_ctrl_or_data_flag   <= iv_pkt_data[126];
                    owt_state             <= DISC_MD1_S;
                end
                else begin                    
                    o_pkt_data_rd         <= 1'b0; 
                    owt_state             <= DISC_MD0_S;
                end            
            end
            DISC_MD1_S:begin
                if(i_pkt_data_empty == 1'b0)begin
                    o_pkt_data_rd         <= 1'b0;                    
                    rv_send_pkt_cnt       <= 11'd0;
                    rv_trans_pkt_cnt      <= 4'd0;
                    owt_state             <= TRANS_1ST_S;
                end
                else begin                    
                    o_pkt_data_rd         <= 1'b0; 
                    owt_state             <= DISC_MD1_S;
                end            
            end             
			TRANS_1ST_S:begin
                if(i_data_ready)begin    
                    rv_send_pkt_cnt        <= rv_send_pkt_cnt + 11'd1;            
                    rv_trans_pkt_cnt       <= rv_trans_pkt_cnt + 4'd1;
                    o_data_wr              <= 1'b1;
                    case(rv_trans_pkt_cnt)
                        4'h0:ov_data[7:0] <= iv_pkt_data[127:120];
                        4'h1:ov_data[7:0] <= iv_pkt_data[119:112];
                        4'h2:ov_data[7:0] <= iv_pkt_data[111:104];
                        4'h3:ov_data[7:0] <= iv_pkt_data[103:96] ;
                        4'h4:ov_data[7:0] <= iv_pkt_data[95:88]  ;					
                        4'h5:ov_data[7:0] <= iv_pkt_data[87:80]  ;
                        4'h6:ov_data[7:0] <= iv_pkt_data[79:72]  ;
                        4'h7:ov_data[7:0] <= iv_pkt_data[71:64]  ;
                        4'h8:ov_data[7:0] <= iv_pkt_data[63:56]  ;
                        4'h9:ov_data[7:0] <= iv_pkt_data[55:48]  ;
                        4'ha:ov_data[7:0] <= iv_pkt_data[47:40]  ;
                        4'hb:ov_data[7:0] <= iv_pkt_data[39:32]  ;
                        4'hc:ov_data[7:0] <= iv_pkt_data[31:24]  ;					
                        4'hd:ov_data[7:0] <= iv_pkt_data[23:16]  ;
                        4'he:ov_data[7:0] <= iv_pkt_data[15:8]   ;	
                        4'hf:ov_data[7:0] <= iv_pkt_data[7:0]    ;
                        default:ov_data[7:0] <= ov_data[7:0];						
                    endcase
                    if(rv_trans_pkt_cnt == 4'b0)begin
                        ov_data[8] <= 1'b1;
                    end
                    else begin
                        ov_data[8] <= 1'b0;
                    end
                    
                    if(rv_trans_pkt_cnt == 4'hf)begin
                        owt_state <= TRANS_PKT_S;
                    end
                    else begin
                        owt_state <= TRANS_1ST_S;
                    end
                    
                    if(rv_trans_pkt_cnt == 4'he)begin
                        o_pkt_data_rd <= 1'b1;	
                    end
                    else begin
                        o_pkt_data_rd <= 1'b0;	
                    end

                    if(rv_trans_pkt_cnt == 4'h0)begin
                        rv_send_sync_clk  <= iv_syn_clk;	
                        rv_send_local_cnt <= iv_local_clk;	
                    end
                    else begin
                        rv_send_sync_clk  <= rv_send_sync_clk;	
                        rv_send_local_cnt <= rv_send_local_cnt;	
                    end
                end
                else begin
                    o_data_wr              <= 1'b0       ;
                    o_pkt_data_rd          <= 1'b0       ;
                    owt_state              <= TRANS_1ST_S;
                end                    
            end	
            TRANS_PKT_S:begin 
                if(i_data_ready)begin    
                    rv_send_pkt_cnt  <= rv_send_pkt_cnt + 11'd1;  
                    rv_trans_pkt_cnt <= rv_trans_pkt_cnt + 4'd1;
                    o_data_wr        <= 1'b1;
                    if((rv_send_pkt_cnt >= 11'd48)&&(rv_send_pkt_cnt <= 11'd63)&&(~r_ctrl_or_data_flag))begin
                        case(rv_trans_pkt_cnt)
                            4'h0:ov_data[7:0] <= rv_send_local_cnt[63:56];//iv_pkt_data[127:120];
                            4'h1:ov_data[7:0] <= rv_send_local_cnt[55:48];//iv_pkt_data[119:112];
                            4'h2:ov_data[7:0] <= rv_send_local_cnt[47:40];//iv_pkt_data[111:104];
                            4'h3:ov_data[7:0] <= rv_send_local_cnt[39:32];//iv_pkt_data[103:96];
                            4'h4:ov_data[7:0] <= rv_send_local_cnt[31:24];//iv_pkt_data[95:88];					
                            4'h5:ov_data[7:0] <= rv_send_local_cnt[23:16];//iv_pkt_data[87:80];
                            4'h6:ov_data[7:0] <= rv_send_local_cnt[15:8] ;//iv_pkt_data[79:72];
                            4'h7:ov_data[7:0] <= rv_send_local_cnt[7:0]  ;//iv_pkt_data[71:64];
                            4'h8:ov_data[7:0] <= rv_send_sync_clk[63:56];//4'h8:ov_data <= iv_pkt_data[63:56];20220817
                            4'h9:ov_data[7:0] <= rv_send_sync_clk[55:48];//4'h9:ov_data <= iv_pkt_data[55:48];
                            4'ha:ov_data[7:0] <= rv_send_sync_clk[47:40];
                            4'hb:ov_data[7:0] <= rv_send_sync_clk[39:32];
                            4'hc:ov_data[7:0] <= rv_send_sync_clk[31:24];					
                            4'hd:ov_data[7:0] <= rv_send_sync_clk[23:16];
                            4'he:ov_data[7:0] <= rv_send_sync_clk[15:8] ;	
                            4'hf:ov_data[7:0] <= rv_send_sync_clk[7:0]  ;
                            default: ov_data[7:0] <= ov_data[7:0];                           
                        endcase
                    end
                    else begin
                        case(rv_trans_pkt_cnt)
                            4'h0:ov_data[7:0] <= iv_pkt_data[127:120];
                            4'h1:ov_data[7:0] <= iv_pkt_data[119:112];
                            4'h2:ov_data[7:0] <= iv_pkt_data[111:104];
                            4'h3:ov_data[7:0] <= iv_pkt_data[103:96];
                            4'h4:ov_data[7:0] <= iv_pkt_data[95:88];					
                            4'h5:ov_data[7:0] <= iv_pkt_data[87:80];
                            4'h6:ov_data[7:0] <= iv_pkt_data[79:72];
                            4'h7:ov_data[7:0] <= iv_pkt_data[71:64];
                            4'h8:ov_data[7:0] <= iv_pkt_data[63:56];
                            4'h9:ov_data[7:0] <= iv_pkt_data[55:48];
                            4'ha:ov_data[7:0] <= iv_pkt_data[47:40];
                            4'hb:ov_data[7:0] <= iv_pkt_data[39:32];
                            4'hc:ov_data[7:0] <= iv_pkt_data[31:24];					
                            4'hd:ov_data[7:0] <= iv_pkt_data[23:16];
                            4'he:ov_data[7:0] <= iv_pkt_data[15:8];	
                            4'hf:ov_data[7:0] <= iv_pkt_data[7:0];
                            default:ov_data[7:0] <= ov_data[7:0];                            
                        endcase                
                    end
                    if(iv_pkt_data[133:132]==2'b10)begin
                        if(iv_pkt_data[131:128] + rv_trans_pkt_cnt == 4'hf)begin
                            owt_state     <= CONTROL_IFG_S;
                            //owt_state     <= IDLE_S;//在此处不能直接跳回到IDLE_S状态，需要再等一拍才能跳回到IDLE_S状态；否则在IDLE_S状态FIFO状态还未改变（由不空变为空）.
                            ov_data[8]    <= 1'b1  ;
                            o_pkt_data_rd <= 1'b1  ;
                        end
                        else begin
                            o_pkt_data_rd <= 1'b0  ;
                            ov_data[8]    <= 1'b0  ;                            
                            owt_state     <= TRANS_PKT_S;
                        end
                    end
                    else begin
                        ov_data[8]    <= 1'b0  ; 
                        owt_state     <= TRANS_PKT_S;                
                        if(rv_trans_pkt_cnt == 4'he)begin
                            o_pkt_data_rd <= 1'b1;	
                        end
                        else begin
                            o_pkt_data_rd <= 1'b0;	
                        end
                    end
                end
                else begin
                    o_data_wr              <= 1'b0       ;
                    o_pkt_data_rd          <= 1'b0       ;
                    owt_state              <= TRANS_PKT_S;                
                end
            end	            
            CONTROL_IFG_S:begin//等一拍再跳回到IDLE_S状态；否则在IDLE_S状态FIFO状态还未改变（由不空变为空）.
			    o_pkt_data_rd    <= 1'b0;	
				ov_data          <= 9'b0;
                o_data_wr	     <= 1'b0;
                rv_trans_pkt_cnt <= 4'h0;
                owt_state        <= IDLE_S;
				//rv_interframe_gap_cnt <= rv_interframe_gap_cnt + 4'd1;
				//if(rv_interframe_gap_cnt <= 4'd14)begin
				//	owt_state <= CONTROL_IFG_S;
				//end
				//else begin
				//	owt_state <= IDLE_S;
				//end
			end		
			default:begin
                ov_data          <= 9'b0;
				o_data_wr        <= 1'b0;
                o_pkt_data_rd    <= 1'b0;                
				rv_trans_pkt_cnt <= 4'h0;
				//rv_interframe_gap_cnt <= 4'd0;
				owt_state        <= IDLE_S;
			end
		endcase
	end
end
endmodule